/* fatfs - U盘接口 */

#include "ff_port.h"
// #include "drv_sdcard.h"
#include "loger.h"

#if (CONFIG_HAL_USB_HOST_CLASS_MSC_ENABLE)
#include "usbh_core.h"
#include "usbh_msc.h"
// #include "bsp_usb.h"
#include "drv_usb.h"


/* define */
#define TAG "FS-UDisk"
#define USB_DEFAULT_BLOCK_SIZE      512


/* static func */




static DSTATUS udisk_init(void)
{
    LOG_I(TAG, "udisk_init finsh");

    return 0;
}

static DSTATUS udisk_deinit(void)
{

    return 0;
}

static DSTATUS udisk_status(void)
{
    DRESULT res = RES_ERROR;
    USBH_HandleTypeDef *usb_host_handle;
    MSC_HandleTypeDef *usb_msc_handle;

    usb_host_handle = drv_usb_host_get_handle();
    usb_msc_handle = usb_host_handle->pActiveClass->pData;
    if (USBH_MSC_UnitIsReady(usb_host_handle, usb_msc_handle->current_lun))
    {
        LOG_I(TAG, "UDisk OK!");
        res = RES_OK;
    }
    else
    {
        LOG_E(TAG, "UDisk Fail!");
        res = RES_ERROR;
    }

    return res;
}

static DRESULT udisk_read(BYTE *buff, DWORD sector, UINT count)
{
    DRESULT res = RES_ERROR;
    MSC_LUNTypeDef info;
    USBH_HandleTypeDef *usb_host_handle;
    MSC_HandleTypeDef *usb_msc_handle;

    usb_host_handle = drv_usb_host_get_handle();
    usb_msc_handle = usb_host_handle->pActiveClass->pData;
    if (USBH_MSC_Read(usb_host_handle, usb_msc_handle->current_lun, sector, buff, count) == USBH_OK)
    {
        res = RES_OK;
    }
    else
    {
        LOG_E(TAG, "UDisk Read Fail!");
        USBH_MSC_GetLUNInfo(usb_host_handle, usb_msc_handle->current_lun, &info);
        switch (info.sense.asc)
        {
        case SCSI_ASC_LOGICAL_UNIT_NOT_READY:
        case SCSI_ASC_MEDIUM_NOT_PRESENT:
        case SCSI_ASC_NOT_READY_TO_READY_CHANGE:
            LOG_E(TAG, "USB Disk is not ready!");
            res = RES_NOTRDY;
            break;
        default:
            res = RES_ERROR;
            break;
        }
    }
    return res;
}

static DRESULT udisk_write(const BYTE *buff, DWORD sector, UINT count)
{
    DRESULT res = RES_ERROR;
    MSC_LUNTypeDef info;
    USBH_HandleTypeDef *usb_host_handle;
    MSC_HandleTypeDef *usb_msc_handle;

    usb_host_handle = drv_usb_host_get_handle();
    usb_msc_handle = usb_host_handle->pActiveClass->pData;
    if (USBH_MSC_Write(usb_host_handle, usb_msc_handle->current_lun, sector, (BYTE *)buff, count) == USBH_OK)
    {
        res = RES_OK;
    }
    else
    {
        LOG_E(TAG, "UDisk Write Fail!");
        USBH_MSC_GetLUNInfo(usb_host_handle, usb_msc_handle->current_lun, &info);
        switch (info.sense.asc)
        {
        case SCSI_ASC_WRITE_PROTECTED:
            LOG_E(TAG, "USB Disk is Write protected!");
            res = RES_WRPRT;
            break;
        case SCSI_ASC_LOGICAL_UNIT_NOT_READY:
        case SCSI_ASC_MEDIUM_NOT_PRESENT:
        case SCSI_ASC_NOT_READY_TO_READY_CHANGE:
            LOG_E(TAG, "USB Disk is not ready!");
            res = RES_NOTRDY;
            break;
        default:
            res = RES_ERROR;
            break;
        }
    }
    return res;
}

static DRESULT udisk_ioctl(BYTE cmd, void *buff)
{
    DRESULT res = RES_ERROR;
    MSC_LUNTypeDef info;
    USBH_HandleTypeDef *usb_host_handle;
    MSC_HandleTypeDef *usb_msc_handle;

    usb_host_handle = drv_usb_host_get_handle();
    usb_msc_handle = usb_host_handle->pActiveClass->pData;
    switch (cmd)
    {
    case CTRL_SYNC:
        res = RES_OK;
        break;
    case GET_SECTOR_COUNT: /* 获取扇区数量 */
        if (USBH_MSC_GetLUNInfo(usb_host_handle, usb_msc_handle->current_lun, &info) == USBH_OK)
        {
            *(DWORD *)buff = info.capacity.block_nbr;
            res = RES_OK;
            LOG_I(TAG, "UDisk sector count = %d", info.capacity.block_nbr);
        }
        else
        {
            res = RES_ERROR;
        }
        break;
    case GET_SECTOR_SIZE: /* 获取扇区大小 */
        if (USBH_MSC_GetLUNInfo(usb_host_handle, usb_msc_handle->current_lun, &info) == USBH_OK)
        {
            *(DWORD *)buff = info.capacity.block_size;
            res = RES_OK;
            LOG_I(TAG, "UDisk sector size = %d", info.capacity.block_size);
        }
        else
        {
            res = RES_ERROR;
        }
        break;
    case GET_BLOCK_SIZE: /* 获取一个扇区里面擦除块的大小 */
        if (USBH_MSC_GetLUNInfo(usb_host_handle, usb_msc_handle->current_lun, &info) == USBH_OK)
        {
            *(DWORD *)buff = info.capacity.block_size / USB_DEFAULT_BLOCK_SIZE;
            LOG_I(TAG, "UDisk block size = %d", info.capacity.block_size / USB_DEFAULT_BLOCK_SIZE);
            res = RES_OK;
        }
        else
        {
            res = RES_ERROR;
        }
        break;
    default:
        res = RES_PARERR;
    }
    return res;
}

/* export */

const _ff_port_opt_t ff_port_udisk = 
{
    .name = "udisk",
    .init = udisk_init,
    .deinit = udisk_deinit,
    .status = udisk_status,
    .read = udisk_read,
    .write = udisk_write,
    .ioctl = udisk_ioctl,
};

#endif
